//
//  GGDFUProtocol.m
//  GGDFU
//
//  Created by 陈志勇 on 17/1/14.
//  Copyright © 2017年 陈志勇. All rights reserved.
//

#import "GGDFUProtocol.h"
#import "GGBaseInfoData.h"
#import "GGMD5.h"

/** 协议头 */
static unsigned char const protocolHead = 0xaa;
/** 协议地址 */
static unsigned char const protocolAdd  = 0xff;

@implementation GGDFUProtocol

#pragma mark - 协议方法
// 应用握手
+ (NSData *)reset
{
    NSData *data = [self hexStringToData:@"7E323046464430463830303030464436300D"];
    return data;
}

// 引导握手
+ (NSData *)shakeHandWithFilePath:(NSString *)filePath
{
    // 计算读取的文件MD5
    NSString *md5 = [GGMD5 getFileMD5WithPath:filePath];
    //MD5共有16个字节，根据协议需要截取MD5的前8个字节当做MD5的校验结果
    md5 = [md5 substringToIndex:16];
    md5 = [NSString stringWithFormat:@"%@0800",md5];
    // 引导握手
    GGBaseInfoData *infoData = [[GGBaseInfoData alloc] init];
    infoData.packetIndex = 0;
    infoData.commandType = GGBaseInfoDataCommandHandShake;
    infoData.infoLength = 10;
    infoData.infoData = [GGDFUProtocol hexStringToData:md5];
    NSData *tempData = [infoData encodeInfoData];
    return [GGDFUProtocol encodeDataWithInfoData:tempData commandType:GGDFUCommandTypeDownload];
}

// 程序下载
+ (NSData *)downloadWithPacketIndex:(NSUInteger)packetIndex infoData:(NSData *)infoData
{
    GGBaseInfoData *baseInfoData = [[GGBaseInfoData alloc] init];
    baseInfoData.packetIndex = packetIndex;
    baseInfoData.commandType = GGBaseInfoDataCommandTpyeDownload;
    baseInfoData.infoLength = [infoData length];
    baseInfoData.infoData = infoData;
    NSData *tempData = [baseInfoData encodeInfoData];
    return [GGDFUProtocol encodeDataWithInfoData:tempData commandType:GGDFUCommandTypeDownload];
}

// 程序完成下载
+ (NSData *)completeWithPacketIndex:(NSUInteger)packetIndex
{
    GGBaseInfoData *baseInfoData = [[GGBaseInfoData alloc] init];
    baseInfoData.packetIndex = packetIndex;
    baseInfoData.commandType = GGBaseInfoDataCommandTpyeComplete;
    baseInfoData.infoLength = 2;
    baseInfoData.infoData = nil;
    NSData *tempData = [baseInfoData encodeInfoData];
    return [GGDFUProtocol encodeDataWithInfoData:tempData commandType:GGDFUCommandTypeDownload];
}

#pragma mark - init
//- (id)init
//{
//
//    if (self=[super init]) {
//        self.bodyData=[[NSMutableData alloc] initWithCapacity:1024];
//    }
//    return self;
//    
//}

#pragma mark - 协议组包、解析
//协议命令组包方式一
+ (NSData *)msrKeyWithCommandType:(unsigned char)commandType //命令字
                          contentInfo:(NSData *)contentInfo  //命令内容
{
    unsigned int contentLen = (unsigned int)[contentInfo length];
    Byte *resultByte = (Byte *)[contentInfo bytes];
    unsigned int pkLen = contentLen; //数据体长度为信息题字节长度，占用2个字节
    unsigned int sum=0;
    unsigned char cmd[pkLen + 11];
    cmd[0] = 0xAA;
    cmd[1] = 0xFF;
    sum += cmd[1];
    cmd[2] = commandType;
    sum += cmd[2];
    cmd[3] = (unsigned char)(pkLen>>8);
    sum += cmd[3];
    cmd[4] = (unsigned char)(pkLen&0x00ff);
    sum += cmd[4];
    for (NSInteger i = 0; i < contentLen; i++) {
        cmd[5 + i] = resultByte[i];
        sum += cmd[5 + i];
    }
    cmd[5+contentLen] = (unsigned char)(sum>>8);
    cmd[6+contentLen] = (unsigned char)(sum&0x00ff);
    
    cmd[7+contentLen] = 0xCC;
    cmd[8+contentLen] = 0x33;
    cmd[9+contentLen] = 0xC3;
    cmd[10+contentLen] = 0x3C;
    
    NSData *data = [[NSData alloc] initWithBytes:&cmd length:pkLen + 11];
    
    return data;
}

// 协议组包方式二
+ (NSData *)encodeDataWithInfoData:(NSData *)infoData commandType:(NSUInteger)commandType
{
    
    NSMutableData *mulData=[NSMutableData dataWithCapacity:1024];
    // 协议头
    [mulData appendBytes:&protocolHead length:1];
    
    // 设备地址
    [mulData appendBytes:&protocolAdd length:1];
    
    // 命令
    [mulData appendBytes:&commandType length:1];
    
    // 数据长度
    Byte *tempData = (Byte *)[infoData bytes];
    NSUInteger length = 0;
    // 数据块的指令是下载，则数据长度为1028
    if (tempData[1] == 0x02 ) {
        length = 1028;
    }else{
        length = (NSUInteger)[infoData length];
    }
    
    Byte c[2];
    c[0] = (length >> 8) & 0xff;
    c[1] = length & 0x00ff;
    [mulData appendBytes:c length:2];
    
    // 数据体
    if (infoData && [infoData length]>0) {
        [mulData appendData:infoData];
    }
    
    // 数据块的指令是下载，则数据需要补FF
    if (tempData[1] == 0x02 && [infoData length]!= 1028) {
//        NSLog(@"infoData的长度:%zd",[infoData length]);
        for (NSUInteger i = 0; i < (1028 - [infoData length]); i++) {
            [mulData appendBytes:&protocolAdd length:1];
        }
    }
    
    // 校验和
    length = [mulData length]; // 重新计算数据块的长度
    Byte *mulDataBytes = (Byte *)[mulData bytes];
    NSUInteger sum = 0;
    for (NSUInteger i = 1; i < length; i++) {
        sum += mulDataBytes[i];
    }
    Byte d[2];
    d[0] = (sum >> 8) & 0xff;
    d[1] = sum & 0x00ff;
    [mulData appendBytes:d length:2];
    
    // 协议尾
    Byte e[4] = {0xcc,0x33,0xc3,0x3c};
    [mulData appendBytes:e length:4];
    
    return mulData;
}

#pragma mark - 解析协议
// 解析校验和
+ (BOOL)parseSumWithResponseData:(NSData *)responseData
{
    // 校验和
    NSUInteger length = [responseData length]; // 计算数据块的长度
    Byte *resultByte = (Byte *)[responseData bytes];
    NSUInteger sum = 0;
    for (NSUInteger i = 1; i < length - 6; i++) {
        sum += resultByte[i];
    }
    
    // 取出校验和的高低低字节
    unsigned char higA = (unsigned char)(sum >> 8);
    unsigned char lowA = (unsigned char)(sum & 0x00ff);
    
    // 比较计算出来的高低字节是否和接收到的校验和一致
    if ((higA == resultByte[length - 6]) && (lowA == resultByte[length - 5])) {
        return YES;
    }else{
        return NO;
    }
    
    
}

// 解析出数据块包
+ (NSData *)parseInfoData:(NSData *)responseData
{
    Byte *responseByte = (Byte *)[responseData bytes];
    NSUInteger infoDataLength = responseByte[4];
    NSData *infoData = [responseData subdataWithRange:NSMakeRange(5, infoDataLength)];
    
    return infoData;
}

// 解析数据块的包编号
+ (NSUInteger)parseInfoDataPacketIndex:(NSData *)infoData
{
    Byte *responseByte = (Byte *)[infoData bytes];
    NSUInteger packetIndex = responseByte[0] * 256 + responseByte[1];
    
    return packetIndex;
}

// 解析数据块的命令执行情况
+ (BOOL)parseCommandResult:(NSData *)infoData
{
    Byte *responseByte = (Byte *)[infoData bytes];
    BOOL isSucceed = responseByte[2];
    
    return isSucceed;
}

// 解析数据块的命令类型

#pragma mark - 数据转换
// data数据转16进制数
+ (NSString *)dataTohexString:(NSData *)responseData
{
    Byte *resultByte = (Byte *)[responseData bytes];
    NSInteger len = [responseData length];
    NSString *hexStr=@"";
    // 1.截取出命令中的内容
    for(int i = 0;i < len;i++){
        NSString *newHexStr = [NSString stringWithFormat:@"%x",resultByte[i]&0xff];///16进制数
        if([newHexStr length]==1)
            hexStr = [NSString stringWithFormat:@"%@0%@",hexStr,newHexStr];
        else
            hexStr = [NSString stringWithFormat:@"%@%@",hexStr,newHexStr];
        
    }
    return hexStr;
}


// 16进制string转成data
+ (NSData *)hexStringToData:(NSString *)str
{
    
    unsigned int contentLen = (unsigned int)[str length];
    
    unsigned char cmd[contentLen / 2];
    //处理命令内容的数据比较复杂,需要先将字nsstring转成char
    unsigned char *uchar;
    
    NSRange range;
    if (contentLen % 2 == 0) {
        range = NSMakeRange(0, 2);
        //NSLog(@"range.location:%ld",range.location);
    } else {
        range = NSMakeRange(0, 1);
        //NSLog(@"range.location:%ld",range.location);
    }
    for (NSInteger i = range.location; i < contentLen; i += 2) {
        unsigned int anInt;
        NSString *hexCharStr = [str substringWithRange:range];
        //NSLog(@"hexCharStr:%@",hexCharStr);
        NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr];
        
        [scanner scanHexInt:&anInt];
        
        NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1];
        //NSLog(@"entity[%ld]:%@",(long)i,entity);
        
        uchar = (unsigned char *)[entity bytes];
        cmd[i / 2] = *uchar;
        range.location += range.length;
        range.length = 2;
    }
    
    
    NSData *data = [[NSData alloc] initWithBytes:&cmd length: contentLen / 2];
    return data;
}

@end
